<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>TableOfContent</title>
</head>

<body>
  <!-- html -->
  <div class="toc__container">
    <div class="toc__name">
      目录
    </div>

    <hr />

    <div class="toc__content" id="target">
      <!-- to inject -->
    </div>

    <div class="toc__content" style="display: none">
      <ul>
        <li>
          <div class="toc__title">1</div>
        </li>
        <li>
          <div class="toc__title">2</div>
          <ul>
            <li>
              <div class="toc__title">2-1</div>
            </li>
            <li>
              <div class="toc__title">2-2</div>
              <ul>
                <li>
                  <div class="toc__title">2-2-1</div>
                </li>
                <li>
                  <div class="toc__title active">2-2-2</div>
                </li>
              </ul>
            </li>
            <li>
              <div class="toc__title">2-3</div>
            </li>
          </ul>
        </li>
        <li>
          <div class="toc__title">3</div>
        </li>
        <li>
          <div class="toc__title">4</div>
        </li>
      </ul>
    </div>
  </div>

  <!-- utils: listToTree -->
  <script>
    function listToTree(list) {
      const tree = [];

      const nodeMap = new Map();
      for (const node of list) {
        nodeMap.set(node.id, {
          children: [],
          ...node
        });
      }

      for (const node of nodeMap.values()) {
        const parent = nodeMap.get(node.pid);
        (parent ? parent.children : tree).push(node);
      }

      return tree;
    }

  </script>

  <!-- data -->
  <script>
    const table = [{
      id: 1,
      name: '引言',
      pid: 0
    },
    {
      id: 2,
      name: '研究现状',
      pid: 0,
      children: [{
        id: 21,
        name: '国内现状',
        pid: 2
      }, {
        id: 22,
        name: '国外现状',
        pid: 1
      }]
    },
    {
      id: 3,
      name: '研究内容',
      pid: 0,
      children: [{
        id: 31,
        name: '成果',
        pid: 3
      }, {
        id: 32,
        name: '创新',
        pid: 3
      }]
    },
    {
      id: 4,
      name: '参考文献',
      pid: 0
    },
    ];

    const tree = listToTree(table);
  </script>

  <!-- template -->
  <script>
    const makeUl = (str) => {
      return `<ul>${str}</ul>`
    }

    const makeLi = (obj) => {
      const { children } = obj;
      let childStr = "";
      if (children?.length) {
        childStr = makeUl(children.map(c => makeLi(c)).join(""))
      }
      return `<li><div class="toc__title">${obj.name}</div>${childStr}</li>`
    }

    const tar = document.querySelector("#target");
    tar.innerHTML = makeUl(tree.map(n => makeLi(n)).join(""));

    const titleElementList = document.querySelectorAll(".toc__title");

    tar.addEventListener("click", function (e) {
      if (e.target.classList.contains('toc__title')) {
        [].forEach.call(titleElementList, e => e.classList.remove('active'));
        e.target.classList.add("active");
      }
    })

  </script>

  <style>
    :root {
      display: flex;
      justify-content: center;
      background-color: #f4f5f5;

      --indent: 24px;
      --color: #000;
      --bg-color: #fff;
      --active-color: #007fff;
      --active-bg-color: #f7f8fa;
    }

    ul,
    li {
      list-style: none;
    }

    ul {
      padding-inline-start: var(--indent);
    }

    .toc__container {
      width: 480px;
      background-color: var(--bg-color);
      color: var(--color);
      padding: 16px;
      position: relative;
    }

    .toc__content>ul {
      padding-inline-start: 0;
    }

    .toc__title {
      padding: 0.4em;
    }

    .toc__title.active, .toc__title:hover {
      color: var(--active-color);
      background-color: var(--active-bg-color);
    }

    .toc__title.active::before {
      color: var(--active-color);
      content: "";
      display: inline-block;
      position: absolute;
      left: 0;
      width: 0.2em;
      height: 1.6em;
      background-color: var(--active-color);
    }

  </style>
</body>

</html>
